#!/usr/bin/python

# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# Implement a pseudo gsm modem.
#
# This modem mimics a GSM modem and allows a user test shill, flimflam
# and UI behaviors when a supported SIM is inserted into the device.
#
# Flimflam Testing
# ================
# To test when running flimflam you can either use an extra ethernet
# port as the pseudo modem network interface, you you create a virtual
# interface.
#
# To use eth0 as your pseudo modem rename it pseudo-modem0:
#   # backchannel setup eth0 pseudo-modem0
#
# and then run the fake modem program:
#   # fake-gsm-modem tmobile
#
# When done, clean up with:
#   # backchannel teardown eth0 pseudo-modem0
#
# Alternatively, you can create a virtual interface which will not
# route packets anywhere, but will allow dhcp to succeed:
#   # ip link add name pseudo-modem0 type veth peer name pseudomodem0p
#
# When done, clean up with:
#   # ip link del pseudo-modem0
#
# Shill Testing
# ================
# To test when running shill, create a virtual interface called
# pseudomodem0:
#
#   # veth pseudomodem0 172.16.1
#
# then run the fake modem program:
#   # fake-gsm-modem -c tmobile --shill --smscount 3 --sms_signal 5
#
# which will start the fake GSM modem and cause shill to receive 3 new SMS
# notifications.  Don't pass --smscount and --sms_signal, if you don't want to
# simulate SMS.
#
# when done, clean up with:
#   # veth teardown pseudomodem0
#

import glib
import gobject
from optparse import OptionParser
import os
import string
import sys

import dbus
import dbus.mainloop.glib


import_path = os.environ.get('SYSROOT', '/usr/local') + '/usr/lib/flimflam/test'
sys.path.append(import_path)

import flimflam_test
GSM_Modem = flimflam_test.GSM_Modem
ModemManager = flimflam_test.ModemManager
SIM = flimflam_test.SIM

DEFAULT_CARRIER = 'att'

# A list of the supported carriers.
SIM_LIST = {
    # Format for adding sims to the dictionary:
    # <Carrier_Name> : SIM( mcc_country = <country>,
    #                       mnc = <MNC>,
    #                       operator_name = <operator name>,
    #                       msin = <MSIN>,
    #                       mcc = <MCC>
    #
    # MCC value is favored over the mcc_country if both are
    # provided.
    'att'       : SIM('us', '090', 'AT&T'),
    'tmobile'   : SIM('us', '026', 'T-Mobile'),
    'simyo'     : SIM('de', '03', 'simyo'),
    'movistar'  : SIM('es', '07', 'Movistar'),
    'sfr'       : SIM('fr', '10', 'SFR'),
    'three'     : SIM('gb', '20', '3'),
    'threeita'  : SIM('it', '99', '3ITA'),
    'kpn'       : SIM('nl', '08', 'KPN'),
}

def make_sms(index, text):
    return {
        'index': index,
        'text' : text or 'Test SMS at %s' % index,
        'number' : '+16175046925',
        'timestamp' : '110919163047-04',
        'smsc' : '+12063130028'
        }

def main():

    usage = '''
Run fake-gsm-modem to simulate a gsm modem with different sims.
This can be used to simpilify the verification process of UI features
that use overseas sims.

To Use:
    1) Device should be read/write and running a test image.
    2) sudo mv /etc/init/cromo.conf
    3) Reboot Device
    4) Connect device using ethernet port and obtain <eth interface name>
    5) cd /usr/local/lib/flimflam/test
    6) ./backchannel setup <eth iface name> pseudo-modem0
    7) ./fake-gsm-modem [--carrier=<carrier name>] &
'''

    parser = OptionParser(usage=usage)
    parser.add_option('-c', '--carrier', dest='carrier_name',
                      metavar='<carrier name>',
                      help='<carrier name> := att | tmobile | simyo | '
                           'movistar | sfr | three | threeita | kpn')
    parser.add_option('-s', '--smscount', dest='sms_count',
                      default=0,
                      metavar='<smscount>',
                      help='<smscount> := integer')
    parser.add_option('-S', '--sms_signal', dest='sms_signal',
                      default=0,
                      metavar='<delay>',
                      help='<delay> := integer number of seconds')
    parser.add_option('-t', '--text', dest='sms_text',
                      default=None,
                      metavar='<text>',
                      help='<text> := text for sms messages')
    parser.add_option('-f', '--file', dest='filename',
                      default=None,
                      metavar='<filename>',
                      help='<filename> := file with text for sms messages')
    parser.add_option('-i', '--shill', dest='shill',
                      default=False,
                      action="store_true",
                      help='use shill device names instead of flimflam names.')

    (options, _) = parser.parse_args()

    if not options.carrier_name:
        options.carrier_name = DEFAULT_CARRIER

    sim_card = SIM_LIST[string.lower(options.carrier_name)]

    smses = {}
    if options.filename:
        f = open(options.filename, 'r')
        for index, line in enumerate(f.readlines()):
            line = line.strip()
            if line:
                smses[index] = make_sms(index, line)
    else:
        for index in xrange(int(options.sms_count)):
            smses[index] = make_sms(index, options.sms_text)

    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
    bus = dbus.SystemBus()
    _ = dbus.service.BusName(flimflam_test.CMM, bus)
    manager = ModemManager(bus, flimflam_test.OCMM)
    device = 'pseudo-modem0'
    if options.shill:
        device = 'pseudomodem0'
    if options.sms_signal == 0:
        initial_smses = smses
    else:
        initial_smses = {}

    testmodem0 = GSM_Modem(manager, '/TestModem/0', gsm_sim=sim_card,
                           smses=initial_smses, device=device)

    if options.sms_signal:
        def AddSmses():
            for sms in smses.values():
                testmodem0.AddSMS(sms)
        glib.timeout_add(1000*int(options.sms_signal), AddSmses)

    mainloop = gobject.MainLoop()
    print "Running test modemmanager."
    mainloop.run()

if __name__ == '__main__':
    main()
